Introduce event controller propagation limits
authorMatthias Clasen <mclasen@redhat.com>
Mon, 29 Apr 2019 02:19:44 +0000 (02:19 +0000)
committerMatthias Clasen <mclasen@redhat.com>
Tue, 28 May 2019 20:25:13 +0000 (20:25 +0000)
Limit event handlers by default to only handle
events targeting the same surface as their widget.

docs/reference/gtk/gtk4-sections.txt
gtk/gtkenums.h
gtk/gtkeventcontroller.c
gtk/gtkeventcontroller.h

index 835f17f26acc4521412af5f1411e19c28d5ff29d..b10d122aab33bc6e2a2ebe5e47828cf9494501b0 100644 (file)
@@ -6522,6 +6522,9 @@ GtkEventController
 GtkPropagationPhase
 gtk_event_controller_get_propagation_phase
 gtk_event_controller_set_propagation_phase
+GtkPropagationLimit
+gtk_event_controller_get_propagation_limit
+gtk_event_controller_set_propagation_limit
 gtk_event_controller_handle_event
 gtk_event_controller_get_widget
 gtk_event_controller_reset
index d18f3f995d05f93199c30c900914919f311851c9..6d1bf81295843218644d0b5c7f24f76ace943994 100644 (file)
@@ -967,6 +967,23 @@ typedef enum
   GTK_PHASE_TARGET
 } GtkPropagationPhase;
 
+/**
+ * GtkPropagationLimit:
+ * @GTK_LIMIT_NONE: Events are handled regardless of what their
+ *   target is.
+ * @GTK_LIMIT_SAME_NATIVE: Events are only handled if their target
+ *   is in the same #GtkNative as the event controllers widget. Note
+ *   that some event types have two targets (origin and destination).
+ *
+ * Describes limits of a #GtkEventController for handling events
+ * targeting other widgets.
+ */
+typedef enum
+{
+  GTK_LIMIT_NONE,
+  GTK_LIMIT_SAME_NATIVE
+} GtkPropagationLimit;
+
 /**
  * GtkEventSequenceState:
  * @GTK_EVENT_SEQUENCE_NONE: The sequence is handled, but not grabbed.
index d085cd58993310a8a70c02d63af32f247534ace8..11e437251793319f6fd08644444af6c2d0237083 100644 (file)
 #include "config.h"
 #include "gtkeventcontroller.h"
 #include "gtkeventcontrollerprivate.h"
+
 #include "gtkwidgetprivate.h"
 #include "gtktypebuiltins.h"
 #include "gtkmarshalers.h"
 #include "gtkprivate.h"
 #include "gtkintl.h"
+#include "gtknative.h"
 
 typedef struct _GtkEventControllerPrivate GtkEventControllerPrivate;
 
 enum {
   PROP_WIDGET = 1,
   PROP_PROPAGATION_PHASE,
+  PROP_PROPAGATION_LIMIT,
   LAST_PROP
 };
 
@@ -52,6 +55,7 @@ struct _GtkEventControllerPrivate
 {
   GtkWidget *widget;
   GtkPropagationPhase phase;
+  GtkPropagationLimit limit;
 };
 
 G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (GtkEventController, gtk_event_controller, G_TYPE_OBJECT)
@@ -79,8 +83,35 @@ gtk_event_controller_filter_event_default (GtkEventController *self,
 {
   GtkEventControllerPrivate *priv = gtk_event_controller_get_instance_private (self);
 
-  if (priv->widget)
-    return !gtk_widget_is_sensitive (priv->widget);
+  if (priv->widget && !gtk_widget_is_sensitive (priv->widget))
+    return TRUE;
+
+  if (priv->limit == GTK_LIMIT_SAME_NATIVE)
+    {
+      GtkWidget *native;
+      GtkWidget *native2;
+      GtkWidget *target;
+
+      native = GTK_WIDGET (gtk_widget_get_native (priv->widget));
+
+      target = GTK_WIDGET (gdk_event_get_target (event));
+      if (target)
+        {
+          native2 = GTK_WIDGET (gtk_widget_get_native (target));
+          if (native == native2)
+            return FALSE;
+        }
+
+      target = GTK_WIDGET (gdk_event_get_related_target (event));
+      if (target)
+        {
+          native2 = GTK_WIDGET (gtk_widget_get_native (target));
+          if (native == native2)
+            return FALSE;
+        }
+
+      return TRUE;
+    }
 
   return FALSE;
 }
@@ -106,6 +137,10 @@ gtk_event_controller_set_property (GObject      *object,
       gtk_event_controller_set_propagation_phase (self,
                                                   g_value_get_enum (value));
       break;
+    case PROP_PROPAGATION_LIMIT:
+      gtk_event_controller_set_propagation_limit (self,
+                                                  g_value_get_enum (value));
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
     }
@@ -128,6 +163,9 @@ gtk_event_controller_get_property (GObject    *object,
     case PROP_PROPAGATION_PHASE:
       g_value_set_enum (value, priv->phase);
       break;
+    case PROP_PROPAGATION_LIMIT:
+      g_value_set_enum (value, priv->limit);
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
     }
@@ -157,6 +195,7 @@ gtk_event_controller_class_init (GtkEventControllerClass *klass)
                            P_("Widget the gesture relates to"),
                            GTK_TYPE_WIDGET,
                            GTK_PARAM_READABLE);
+
   /**
    * GtkEventController:propagation-phase:
    *
@@ -170,6 +209,19 @@ gtk_event_controller_class_init (GtkEventControllerClass *klass)
                          GTK_PHASE_BUBBLE,
                          GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
 
+  /**
+   * GtkEventController:propagation-limit:
+   *
+   * The limit for which events this controller will handle.
+   */
+  properties[PROP_PROPAGATION_LIMIT] =
+      g_param_spec_enum ("propagation-limit",
+                         P_("Propagation limit"),
+                         P_("Propagation limit for events handled by this controller"),
+                         GTK_TYPE_PROPAGATION_LIMIT,
+                         GTK_LIMIT_SAME_NATIVE,
+                         GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
+
   g_object_class_install_properties (object_class, LAST_PROP, properties);
 }
 
@@ -180,6 +232,7 @@ gtk_event_controller_init (GtkEventController *controller)
 
   priv = gtk_event_controller_get_instance_private (controller);
   priv->phase = GTK_PHASE_BUBBLE;
+  priv->limit = GTK_LIMIT_SAME_NATIVE;
 }
 
 /**
@@ -311,3 +364,32 @@ gtk_event_controller_set_propagation_phase (GtkEventController  *controller,
 
   g_object_notify_by_pspec (G_OBJECT (controller), properties[PROP_PROPAGATION_PHASE]);
 }
+
+GtkPropagationLimit
+gtk_event_controller_get_propagation_limit (GtkEventController *controller)
+{
+  GtkEventControllerPrivate *priv;
+
+  g_return_val_if_fail (GTK_IS_EVENT_CONTROLLER (controller), GTK_LIMIT_SAME_NATIVE);
+
+  priv = gtk_event_controller_get_instance_private (controller);
+
+  return priv->limit;
+}
+void
+gtk_event_controller_set_propagation_limit (GtkEventController  *controller,
+                                            GtkPropagationLimit  limit)
+{
+  GtkEventControllerPrivate *priv;
+
+  g_return_if_fail (GTK_IS_EVENT_CONTROLLER (controller));
+
+  priv = gtk_event_controller_get_instance_private (controller);
+
+  if (priv->limit == limit)
+    return;
+
+  priv->limit = limit;
+
+  g_object_notify_by_pspec (G_OBJECT (controller), properties[PROP_PROPAGATION_LIMIT]);
+}
index f2f2b6a2b0932633c8b952c87c5b05d011b1b41c..963f440e6a24175fa9320e2b1113e7604343bf64 100644 (file)
@@ -59,6 +59,12 @@ GDK_AVAILABLE_IN_ALL
 void                gtk_event_controller_set_propagation_phase (GtkEventController  *controller,
                                                                 GtkPropagationPhase  phase);
 
+GDK_AVAILABLE_IN_ALL
+GtkPropagationLimit gtk_event_controller_get_propagation_limit (GtkEventController *controller);
+
+GDK_AVAILABLE_IN_ALL
+void                gtk_event_controller_set_propagation_limit (GtkEventController  *controller,
+                                                                GtkPropagationLimit  limit);
 G_END_DECLS
 
 #endif /* __GTK_EVENT_CONTROLLER_H__ */